package com.jieshuibao.service;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.http.client.ClientProtocolException;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import com.jieshuibao.common.bokecc.bean.ChunkInfo;
import com.jieshuibao.common.bokecc.bean.LiveRoomInfo;
import com.jieshuibao.common.bokecc.bean.LiveRoomStatus;
import com.jieshuibao.common.bokecc.bean.MetaInfo;
import com.jieshuibao.common.bokecc.bean.UploadReq;
import com.jieshuibao.common.bokecc.bean.UploadRes;
import com.jieshuibao.common.bokecc.bean.User;
import com.jieshuibao.common.bokecc.bean.VedioInfo;
import com.jieshuibao.common.bokecc.bean.VerifyRes;
import com.jieshuibao.common.bokecc.bean.Video;
import com.jieshuibao.common.bokecc.config.Config;
import com.jieshuibao.common.bokecc.util.APIServiceFunction;
import com.jieshuibao.common.config.Global;
import com.jieshuibao.util.JsonUtil;
import com.jieshuibao.util.StringUtils;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

@Service
public class BokeccService{
	
	private static final Logger log = Logger.getLogger(BokeccService.class);
	
	private static int length = 4*1024*1024;
	
	
	@Resource
	private RedisService redisService;
	@Resource
	private HttpClientService httpClientService;
	
	/**
	 * 组装get请求参数
	 * @param paramsMap  参数
	 * @param salt       点播    直播加密key
	 * @return
	 */
	public String assemblyParam(Map<String, String> paramsMap,String salt) {
		long time = System.currentTimeMillis();
		String requestURL = APIServiceFunction.createHashedQueryString(
				paramsMap, time, salt);
		return requestURL;
	}
	/**
	 * 创建上传视频信息  获取meta  chunk
	 * @param uploadReq
	 * @return  {"uploadinfo":{"videoid":"9DEF3D5E5DE28F569C33DC5901307461","userid":"A0123BC413D6FBAE","servicetype":"240593F08992E06B","metaurl":"http://3-15-vacombiner.bokecc.com/servlet/uploadmeta","chunkurl":"http://3-15-vacombiner.bokecc.com/servlet/uploadchunk"}}
	 */
	public VedioInfo createVedio(UploadReq uploadReq){
		Map<String, String> paramsMap = new HashMap<String, String>();
		paramsMap.put("userid", Config.userid);
		paramsMap.put("notify_url", Config.notify_url+"?md5="+uploadReq.getMd5());
		paramsMap.put("format", "json");
		paramsMap.put("title", uploadReq.getTitle());
		paramsMap.put("tag", uploadReq.getTag());
		paramsMap.put("description", uploadReq.getDescription());
		paramsMap.put("categoryid", uploadReq.getCategoryid());
		paramsMap.put("filename", uploadReq.getFilename());
		paramsMap.put("filesize", String.valueOf(uploadReq.getFilesize()));
		String requestURL = assemblyParam(paramsMap,Config.key);
		VedioInfo vedioInfo = null;
		try {
			String result = httpClientService.doGet(Config.api_createVideo + "?" + requestURL);
			log.info("createVedio recived data:"+result);
			JSONObject obj = JsonUtil.str2Obj(result);
			Object object = obj.get("uploadinfo");
			vedioInfo = JsonUtil.json2Bean(JsonUtil.toJson(object), VedioInfo.class);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return vedioInfo;
	}
	/**
	 * 上传meta
	 * @param vedioInfo
	 * @return
	 */
	public MetaInfo uploadmeta(VedioInfo vedioInfo,String first,UploadReq uploadReq){
		Map<String, String> paramsMap = new HashMap<String, String>();
		paramsMap.put("uid", Config.userid);
		paramsMap.put("format", "json");
		paramsMap.put("ccvid", vedioInfo.getVideoid());
		paramsMap.put("first", first);
		paramsMap.put("filename", uploadReq.getFilename());
		paramsMap.put("md5", uploadReq.getMd5());
		paramsMap.put("filesize", String.valueOf(uploadReq.getFilesize()));
		paramsMap.put("servicetype", vedioInfo.getServicetype());
		String requestURL = assemblyParam(paramsMap,Config.key);
		MetaInfo metaInfo = null;
		try {
			String result = httpClientService.doGet(vedioInfo.getMetaurl() + "?" + requestURL);
			log.info("uploadmeta recived data:"+result);
			metaInfo = JsonUtil.json2Bean(result, MetaInfo.class);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return metaInfo;
	}
	
	  
    /* url为/servlet/uploadchunk?ccvid=&format= */
    /* chunkStart为chunk起始位置*/
    /* chunkEnd为chunk结束位置*/
    /* file为文件*/
    /* bufferOut为实际文件输出二进制内容*/

 	public String uploadchunk(VedioInfo vedioInfo, int chunkStart, int chunkEnd, File file) {
// 		chunkEnd = 1024 * 1024 *2 -1;
 		byte[] bufferOut = null;
 		try {
			bufferOut = readChunk(file, chunkStart, chunkEnd);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		if(bufferOut == null) {
			System.out.println("---------------read file chunk error-----------------");
			return "read file error";
		}
 		Map<String, String> paramsMap = new HashMap<String, String>();
		paramsMap.put("ccvid", vedioInfo.getVideoid());
		paramsMap.put("format", "json");
		String requestURL = assemblyParam(paramsMap,Config.key);
 		String url = vedioInfo.getChunkurl() +"?"+requestURL;
		HttpURLConnection conn = null;
		try {
			String BOUNDARY = "---------CCHTTPAPIFormBoundaryEEXX" + new Random().nextInt(65536); // 定义数据分隔线
			URL openUrl = new URL(url);
			conn = (HttpURLConnection)openUrl.openConnection();
			// 发送POST请求必须设置如下两行
			conn.setDoOutput(true);
			conn.setDoInput(true);
			conn.setUseCaches(false);
			conn.setRequestMethod("POST");
			conn.setRequestProperty("connection", "Keep-Alive");
			conn.setRequestProperty("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4)");
			conn.setRequestProperty("Charsert", "UTF-8");
			conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
			// content-range
			conn.setRequestProperty("Content-Range", "bytes " + chunkStart + "-" + chunkEnd + "/" + file.length());

			OutputStream out = new DataOutputStream(conn.getOutputStream());
			StringBuilder sb = new StringBuilder();
			sb.append("--").append(BOUNDARY).append("\r\n");
			sb.append("Content-Disposition: form-data;name=\"file" + file.getName() + "\";filename=\"" + file.getName()
					+ "\"\r\n");
			sb.append("Content-Type: application/octet-stream\r\n");
			sb.append("\r\n");
			byte[] data = sb.toString().getBytes();
			out.write(data);
			out.write(bufferOut);
			out.write("\r\n".getBytes());
			// 定义最后数据分隔线
			byte[] end_data = ("--" + BOUNDARY + "--\r\n").getBytes();
			out.write(end_data);
			out.flush();
			out.close();

			// 定义BufferedReader输入流来读取URL的响应
			BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			StringBuffer resultBuf = new StringBuffer("");
			String line = null;
			while ((line = reader.readLine()) != null) {
				resultBuf.append(line);
			}
			reader.close();
			conn.disconnect();
			log.info("uploadchunk recived data:"+JsonUtil.toJson(resultBuf.toString()));
			return resultBuf.toString();
		} catch (Exception e) {
			System.out.println("发送POST请求出现异常！" + e);
			e.printStackTrace();
		} finally {
			if (conn != null)
				conn.disconnect();
		}
		return null;
	}
 	
 	public static byte[] readChunk(File file, int chunkStart, int chunkEnd) throws IOException{
		if(file == null) {
			throw new IOException("The file does not exist");
		}
		long fileLength = file.length();
		if(chunkStart >= fileLength) {
			throw new IOException("Start position > file length");
		}
		RandomAccessFile accessFile = null;
		try {
			int chunksLen = chunkEnd - chunkStart + 1;
			byte[] chunks = new byte[chunksLen];
			accessFile = new RandomAccessFile(file, "r");
			accessFile.seek(chunkStart);
			int readLength = accessFile.read(chunks, 0, chunksLen);
			log.info("read Length: " + readLength);
			accessFile.close();
			return chunks;
		} finally {
			if(accessFile != null) {
				try {
					accessFile.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
 	
	public void vedioUpload(UploadReq uploadReq) {
		File file =  uploadReq.getFile();
		int length2 = (int) file.length();
//		byte[] bufferOut = new byte[length2];
		ChunkInfo chunkInfo = null;
		
		VedioInfo vedioInfo = createVedio(uploadReq);
		if(null == vedioInfo){
			log.error("createVedio error :");
			return;
		}
		MetaInfo metaInfo = uploadmeta(vedioInfo, "1",uploadReq);
		int received = 0;
		try {
			if(metaInfo.getResult()==0){
				if(length2 <= length){
					String res = uploadchunk(vedioInfo, 0, length2-1, file);
					chunkInfo = JsonUtil.json2Bean(res, ChunkInfo.class);
					if(chunkInfo.getResult()==0){
						return;
					}else{
						log.error("uploadchunk min vedio error :"+chunkInfo.getMsg());
						return;
					}
				}
				String res = uploadchunk(vedioInfo, 0, length-1, file);
				chunkInfo = JsonUtil.json2Bean(res, ChunkInfo.class);
				received = chunkInfo.getReceived();
				int chunkEnd = 0;
				do{
					chunkEnd = received+length-1;
					if(chunkEnd >= length2){
						chunkEnd = length2-1;
					}
					if(chunkInfo.getResult() == 0){
						received = chunkInfo.getReceived();
						res = uploadchunk(vedioInfo, received, chunkEnd, file);
						chunkInfo = JsonUtil.json2Bean(res, ChunkInfo.class);
					}else{
						MetaInfo metaInfo2 = uploadmeta(vedioInfo, "2",uploadReq);
						if(metaInfo2.getResult() == 0){
							received = metaInfo2.getReceived();
							res = uploadchunk(vedioInfo, received, chunkEnd, file);
							chunkInfo = JsonUtil.json2Bean(res, ChunkInfo.class);
						}else{
							log.error("uploadmeta error :"+metaInfo.getMsg());
							return;
						}
					}
					log.info("chunkEnd:"+chunkEnd+"-----file length end:"+(length2-1));
				}while(chunkEnd < length2-1);
			}else{
				log.error("uploadmeta error :"+metaInfo.getMsg());
				return;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public UploadRes vedioUpload2(UploadReq uploadReq,HttpServletRequest request){
//		Admin admin = (Admin) request.getSession().getAttribute("loginUser");
		UploadRes uploadRes = new UploadRes();
		File file =  uploadReq.getFile();
		
		VedioInfo vedioInfo = createVedio(uploadReq);
		if(null == vedioInfo){
			log.error("createVedio error :");
			uploadRes.setCode(Global.FALSE);
			uploadRes.setDes("createVedio error in cc");
			return uploadRes;
		}
//		DramaResource dramaResourceByVid = dramaResourceService.getDramaResourceByVid(vedioInfo.getVideoid());
//		if(null == dramaResourceByVid){
//			dramaResourceService.insertDramaResource(vedioInfo,uploadReq,admin);
//		}
		
		MetaInfo metaInfo = uploadmeta(vedioInfo, "1",uploadReq);
		ChunkInfo chunkInfo = null;
		if(metaInfo.getResult()==0){
			int total = (int) file.length();
			if(total <= length){
				String res = uploadchunk(vedioInfo, 0, total-1, file);
				chunkInfo = JsonUtil.json2Bean(res, ChunkInfo.class);
				if(chunkInfo.getResult()==0){
					uploadRes.setCode(Global.TRUE);
					uploadRes.setDes("上传成功");
					return uploadRes;
				}else{
					log.error("uploadchunk min vedio error :"+chunkInfo.getMsg());
					uploadRes.setCode(Global.FALSE);
					uploadRes.setDes("上传失败");
					return uploadRes;
				}
			}
			int start = 0;
			while(start < total){
				if(start+length < total){
					String res = uploadchunk(vedioInfo, start, start+length-1, file);
					chunkInfo = JsonUtil.json2Bean(res, ChunkInfo.class);
					if(null != chunkInfo && chunkInfo.getResult()==0){
						start += length;
					}else{
						log.error("uploadchunk error start with:"+start);
						uploadRes.setCode(Global.FALSE);
						uploadRes.setDes("上传失败");
						return uploadRes;
					}
				}else{
					//最后一块
					String res = uploadchunk(vedioInfo, start, total-1, file);
					chunkInfo = JsonUtil.json2Bean(res, ChunkInfo.class);
					if(null != chunkInfo && chunkInfo.getResult()==0){
						uploadRes.setCode(Global.TRUE);
						uploadRes.setDes("上传成功");
						return uploadRes;
					}else{
						log.error("uploadchunk last chunk error start with:"+start);
						uploadRes.setCode(Global.FALSE);
						uploadRes.setDes("上传失败");
						return uploadRes;
					}
				}
				log.info("start:"+start+"(byte)-----total:"+total+"(byte)");
			}
			uploadRes.setCode(Global.TRUE);
			uploadRes.setDes("上传成功");
			return uploadRes;
		}else{
			log.error("uploadmeta error :"+metaInfo.getMsg());
			uploadRes.setCode(Global.FALSE);
			uploadRes.setDes("上传失败");
			return uploadRes;
		}
	}
	/**
	 * 获取cc注册的用户基本信息
	 * @return
	 */
	public User userinfo(){
		Map<String, String> paramsMap = new HashMap<String, String>();
		paramsMap.put("userid", Config.userid);
		paramsMap.put("format", "json");
		String requestURL = assemblyParam(paramsMap,Config.key);
		//get方式
		String responsestr = null;
		User user = null;
		try {
			responsestr = httpClientService.doGet(Config.api_user + "?" + requestURL);
			user = JsonUtil.fromJson(responsestr, User.class);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		log.info("bokecc userinfo 返回信息："+responsestr);
		return user;
	}
	/**
	 * 获取单个视频信息
	 * @param vedioId
	 * @return
	 */
	public Video vedioinfo(String vedioId){
		Map<String, String> paramsMap = new HashMap<String, String>();
		paramsMap.put("userid", Config.userid);
		paramsMap.put("videoid", vedioId);
		paramsMap.put("format", "json");
		String requestURL = assemblyParam(paramsMap,Config.key);
		Video video = null;
		try {
			String result = httpClientService.doGet(Config.api_videov2 + "?" + requestURL);
			log.info(result);
			JSONObject obj = JsonUtil.str2Obj(result);
			Object object = obj.get("video");
			video = JsonUtil.json2Bean(JsonUtil.toJson(object), Video.class);
			log.info(video.getId());
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return video;
	}
	/**
	 * 视频播放授权
	 * @param vid
	 * @param verificationcode
	 * @return
	 */
	public VerifyRes verify(String vid, String verificationcode) {
		VerifyRes res = new VerifyRes();
		String str = redisService.get(verificationcode);
		log.info("接收到的verificationcode:"+verificationcode+"------vid:"+vid);
		log.info("缓存中获取到的vid:"+str);
		if(StringUtils.isNotEmpty(str)&&StringUtils.isNotEmpty(verificationcode)&& vid.equals(str)){
			res.setEnable(1);
		}else{
			res.setEnable(0);
		}
		res.setMessage("");
		res.setCallback("");
		return res;
	}
	/**
	 * 直播间状态
	 * @param roomArr
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "deprecation" })
	public LiveRoomStatus liveRoomStatus(String[] roomArr){
		String doGet = null;
		if(null != roomArr && roomArr.length>0){
			String roomids = StringUtils.join(roomArr, ",");
			Map<String, String> paramsMap = new HashMap<String, String>();
			paramsMap.put("userid", Config.userid);
			paramsMap.put("roomids", roomids);
			paramsMap.put("format", "json");
			String requestURL = assemblyParam(paramsMap,Config.livekey);
			try {
				doGet = httpClientService.doGet(Config.api_liveroomstatus + "?" + requestURL);
				System.out.println("直播间状态：===="+doGet);
			} catch (ClientProtocolException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		JSONObject obj = JsonUtil.str2Obj(doGet);
		String result = (String) obj.get("result");
		if("OK".equals(result)){
			JSONArray arr = (JSONArray) obj.get("rooms");
			if(null != arr && arr.size()>0){
				List<LiveRoomStatus> list = JSONArray.toList(arr, LiveRoomStatus.class);
				return list.get(0);
			}
		}
		return null;
	}
	/**
	 * 直播间信息
	 * @param roomId
	 * @return
	 */
	public LiveRoomInfo liveRoomInfo(String roomId){
		String doGet = null;
		Map<String, String> paramsMap = new HashMap<String, String>();
		paramsMap.put("userid", Config.userid);
		paramsMap.put("roomid", roomId);
		paramsMap.put("format", "json");
		String requestURL = assemblyParam(paramsMap,Config.livekey);
		try {
			doGet = httpClientService.doGet(Config.api_liveinfo + "?" + requestURL);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		/**
		 * {"result":"OK","room":{"id":"7B7EAB3BFC6D4B949C33DC5901307461","name":"生产环境直播间","desc":"<p>生产环境直播间<\/p>","status":10,"publisherPass":"123123","playPass":"123123","assistantPass":"123123","checkUrl":"","templateType":2,"authType":1,"barrage":0,"foreignPublish":0,"openHostMode":"1","openLowDelayMode":"0","delayTime":"3","showUserCount":"1","dvr":"0","multiQuality":"0"}}
		 */
		JSONObject obj = JsonUtil.str2Obj(doGet);
		String result = (String) obj.get("result");
		if("OK".equals(result)){
			JSONObject roominfo = (JSONObject) obj.get("room");
			LiveRoomInfo liveRoomInfo = JsonUtil.json2Bean(roominfo.toString(), LiveRoomInfo.class);
			return liveRoomInfo;
		}
		return null;
	}
}
